function crop(){
    function Selection(x, y, w, h) {
        this.x = x; // initial positions
        this.y = y;
        this.w = w; // and size
        this.h = h;

        this.px = x; // extra variables to dragging calculations
        this.py = y;
        this.pw = w; // extra variables to dragging calculations
        this.ph = h;

        this.csize = 6; // resize cubes size
        this.csizeh = 10; // resize cubes size (on hover)

        this.iCSize = [this.csize, this.csize, this.csize, this.csize]; // resize cubes sizes
        this.bDrag = [false, false, false, false]; // drag statuses
        this.bDragAll = false; // drag whole selection
    }
    // define Selection draw method
    Selection.prototype.draw = function() {
        ctx.strokeStyle = '#000';
        ctx.lineWidth = 2;
        ctx.strokeRect(this.x, this.y, this.w, this.h);

        // draw part of original image
        if (this.w > 0 && this.h > 0) {
            ctx.drawImage(image, this.x * scale, this.y * scale, this.w * scale, this.h * scale, this.x, this.y, this.w, this.h);
        }

        // draw resize cubes
        ctx.fillStyle = '#fff';
        ctx.fillRect(this.x - this.iCSize[0], this.y - this.iCSize[0], this.iCSize[0] * 2, this.iCSize[0] * 2);
        ctx.fillRect(this.x + this.w - this.iCSize[1], this.y - this.iCSize[1], this.iCSize[1] * 2, this.iCSize[1] * 2);
        ctx.fillRect(this.x + this.w - this.iCSize[2], this.y + this.h - this.iCSize[2], this.iCSize[2] * 2, this.iCSize[2] * 2);
        ctx.fillRect(this.x - this.iCSize[3], this.y + this.h - this.iCSize[3], this.iCSize[3] * 2, this.iCSize[3] * 2);
    }
    // variables
    var scale;
    var canvas, ctx, parent;
    var image;
    var iMouseX, iMouseY, pMouseX, pMouseY;
    var theSelection;
    this.fixed = false
    var that = this
    this.init = function(container,w,h) {
        // if(!container)container = createContainer()
        if(w&&h){
            this.fixed = true
            this.ratio = h/w
        }
        if (!canvas) {
            parent = container
            canvas = document.createElement("canvas");
            canvas.attributes.id = "canvashead";
            canvas.id = "canvashead";
            canvas.style.border = "1px solid #000";
            canvas.width = container.offsetWidth;
            canvas.height = container.offsetHeight - 52;
            ctx = canvas.getContext("2d");
            bind();
            container.appendChild(canvas);
        } else if (parent != container) {
            parent = container
            container.appendChild(canvas);
        }
        if(container){
            canvas.width = container.offsetWidth;
            canvas.height = container.offsetHeight - 52;
        }
    }
    this.setImage = function(src) {
        image = new Image();
        image.onload = function() {
            scale = image.naturalWidth / canvas.width;
            var tmp = image.naturalHeight / canvas.height;
            if (tmp > scale) {
                scale = tmp;
                canvas.width = canvas.height * image.naturalWidth / image.naturalHeight;
            } else {
                canvas.height = canvas.width * image.naturalHeight / image.naturalWidth;
            }
            var top = (canvas.parentElement.offsetHeight - 52 - canvas.height) / 2;
            canvas.style.marginTop = top + 'px';
            var w = (canvas.width < canvas.height ? canvas.width : canvas.height) / 2;
            theSelection = new Selection(0, 0, w, that.ratio?w*that.ratio:w);
            drawScene()
        }
        image.src = src;
    }


    function drawScene() { // main drawScene function
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // clear canvas

        // draw source image
        ctx.drawImage(image, 0, 0, ctx.canvas.width, ctx.canvas.height);

        // and make it darker
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

        // draw selection
        theSelection.draw();
    }

    function getOffset(e) {
        if (!e || typeof e.offsetTop == "undefined"||window.getComputedStyle(e).position=="fixed") return {
            top: 0,
            left: 0
        }
        var o = getOffset(e.parentNode);
        return {
            top: e.offsetTop + o.top,
            left: e.offsetLeft + o.left
        }
    }

    function nofixsize(fx,fy) {
        // in case of dragging of resize cubes
        var iFW, iFH,iFX,iFY;
        if (theSelection.bDrag[0]) {
            fx=-fx
            fy=-fy
            if (theSelection.px - fx < 0)
                fx = theSelection.px;
            if (theSelection.py - fy < 0)
                fy = theSelection.py;
            iFY = theSelection.py - fy;
            iFX = theSelection.px - fx;
            iFW = theSelection.pw + fx;
            iFH = theSelection.ph + fy;
        }
        if (theSelection.bDrag[1]) {
            fy=-fy
            iFX = theSelection.px;
            if (theSelection.py - fy < 0)
                fy = theSelection.py;
            if (theSelection.x + theSelection.pw + fx > canvas.width)
                fx = canvas.width - theSelection.x - theSelection.pw;
            iFY = theSelection.py - fy;
            iFW = theSelection.pw + fx;
            iFH = theSelection.ph + fy;
        }
        if (theSelection.bDrag[2]) {
            iFX = theSelection.x;
            iFY = theSelection.y;
            var x = theSelection.x + theSelection.pw + fx;
            if (x > canvas.width)
                fx = canvas.width - theSelection.x - theSelection.pw;
            var y = theSelection.y + theSelection.ph + fy;
            if (y > canvas.height)
                fy = canvas.height - theSelection.y - theSelection.ph;
            iFW = theSelection.pw + fx;
            iFH = theSelection.ph + fy;
        }
        if (theSelection.bDrag[3]) {
            fx=-fx
            iFY = theSelection.py;
            if (theSelection.px - fx < 0)
                fx = theSelection.px;
            if (theSelection.y + theSelection.ph + fx > canvas.height)
                fy = canvas.height - theSelection.y - theSelection.ph;
            iFX = theSelection.px - fx;
            iFW = theSelection.pw + fx;
            iFH = theSelection.ph + fy;
        }

        if (iFW > theSelection.csizeh * 2 && iFH > theSelection.csizeh * 2) {
            theSelection.w = iFW;
            theSelection.h = iFH;

            theSelection.x = iFX;
            theSelection.y = iFY;
        }
    }

    function fixsize(fx, fy) {
        // in case of dragging of resize cubes
        var iFW, iFH,iFX,iFY,f;
        if (theSelection.bDrag[0]) {
            f = (-fx - fy/that.ratio) / 2;
            if (theSelection.px - f < 0)
                f = theSelection.px;
            if (theSelection.py - f < 0)
                f = theSelection.py;
            iFY = theSelection.py - f*that.ratio;
            iFX = theSelection.px - f;
            iFW = theSelection.pw + f;
            iFH = theSelection.ph + f;
        }
        if (theSelection.bDrag[1]) {
            f = (fx - fy/that.ratio) / 2;
            iFX = theSelection.px;
            if (theSelection.py - f < 0)
                f = theSelection.py;
            if (theSelection.x + theSelection.pw + f > canvas.width)
                f = canvas.width - theSelection.x - theSelection.pw;
            iFY = theSelection.py - f;
            iFW = theSelection.pw + f;
            iFH = theSelection.ph + f*that.ratio;
        }
        if (theSelection.bDrag[2]) {
            f = (fx + fy/that.ratio) / 2;
            iFX = theSelection.x;
            iFY = theSelection.y;
            var x = theSelection.x + theSelection.pw + f;
            if (x > canvas.width)
                f = canvas.width - theSelection.x - theSelection.pw;
            var y = theSelection.y + theSelection.ph + f;
            if (y > canvas.height)
                f = canvas.height - theSelection.y - theSelection.ph;
            iFW = theSelection.pw + f;
            iFH = theSelection.ph + f*that.ratio;
        }
        if (theSelection.bDrag[3]) {
            f = (-fx + fy/that.ratio) / 2;
            iFY = theSelection.py;
            if (theSelection.px - f < 0)
                f = theSelection.px;
            if (theSelection.y + theSelection.ph + f > canvas.height)
                f = canvas.height - theSelection.y - theSelection.ph;
            iFX = theSelection.px - f;
            iFW = theSelection.pw + f;
            iFH = theSelection.ph + f*that.ratio;
        }

        if (iFW > theSelection.csizeh * 2 && iFH > theSelection.csizeh * 2) {
            theSelection.w = iFW;
            theSelection.h = iFH;

            theSelection.x = iFX;
            theSelection.y = iFY;
        }
    }

    function bind() {
        function move(e){
            if(!theSelection)return;
            var offset = getOffset(canvas);
            iMouseX = Math.floor(e.clientX - offset.left);
            iMouseY = Math.floor(e.clientY - offset.top);
            var fx = iMouseX - pMouseX;
            var fy = iMouseY - pMouseY;
            // in case of drag of whole selector
            if (theSelection&&theSelection.bDragAll) {
                var x = theSelection.px + fx;
                var y = theSelection.py + fy;
                if (x < 0)
                    theSelection.x = 0;
                else if (x + theSelection.w > canvas.width)
                    theSelection.x = canvas.width - theSelection.w;
                else
                    theSelection.x = x;
                if (y < 0)
                    theSelection.y = 0;
                else if (y + theSelection.h > canvas.height)
                    theSelection.y = canvas.height - theSelection.h;
                else
                    theSelection.y = y;
            }

            if(that.fixed)fixsize(fx, fy);
            else nofixsize(fx,fy)
            drawScene();
        }
        function down(e){
            var offset = getOffset(canvas);
            iMouseX = pMouseX = Math.floor(e.clientX - offset.left);
            iMouseY = pMouseY = Math.floor(e.clientY - offset.top);

            theSelection.px = theSelection.x;
            theSelection.py = theSelection.y;
            theSelection.pw = theSelection.w;
            theSelection.ph = theSelection.h;

            if (iMouseX > theSelection.x - theSelection.csizeh && iMouseX < theSelection.x + theSelection.csizeh &&
                iMouseY > theSelection.y - theSelection.csizeh && iMouseY < theSelection.y + theSelection.csizeh) {
                theSelection.bDrag[0] = true;
                theSelection.iCSize[0] = theSelection.csizeh;
            }
            if (iMouseX > theSelection.x + theSelection.w - theSelection.csizeh && iMouseX < theSelection.x + theSelection.w + theSelection.csizeh &&
                iMouseY > theSelection.y - theSelection.csizeh && iMouseY < theSelection.y + theSelection.csizeh) {
                theSelection.bDrag[1] = true;
                theSelection.iCSize[1] = theSelection.csizeh;
            }
            if (iMouseX > theSelection.x + theSelection.w - theSelection.csizeh && iMouseX < theSelection.x + theSelection.w + theSelection.csizeh &&
                iMouseY > theSelection.y + theSelection.h - theSelection.csizeh && iMouseY < theSelection.y + theSelection.h + theSelection.csizeh) {
                theSelection.bDrag[2] = true;
                theSelection.iCSize[2] = theSelection.csizeh;
            }
            if (iMouseX > theSelection.x - theSelection.csizeh && iMouseX < theSelection.x + theSelection.csizeh &&
                iMouseY > theSelection.y + theSelection.h - theSelection.csizeh && iMouseY < theSelection.y + theSelection.h + theSelection.csizeh) {
                theSelection.bDrag[3] = true;
                theSelection.iCSize[3] = theSelection.csizeh;
            }

            if (iMouseX > theSelection.x + theSelection.csizeh && iMouseX < theSelection.x + theSelection.w - theSelection.csizeh &&
                iMouseY > theSelection.y + theSelection.csizeh && iMouseY < theSelection.y + theSelection.h - theSelection.csizeh) {
                theSelection.bDragAll = true;
            }
        }
        function up(){
            theSelection.bDragAll = false;
            for (var i = 0; i < 4; i++) {
                theSelection.bDrag[i] = false;
                theSelection.iCSize[i] = theSelection.csize;
            }
            theSelection.px = 0;
            theSelection.py = 0;
            drawScene();
        }
        canvas.addEventListener("touchmove", function(event) { // binding mouse move event
            event.preventDefault();
            var e = event.touches[0];
            move(e)
        });
        parent.addEventListener("mousemove", function(event) { // binding mouse move event
            event.preventDefault();
            move(event)
        });

        canvas.addEventListener("touchstart", function(event) { // binding mousedown event
            event.preventDefault();
            var e = event.touches[0];
            down(e)
        });
        parent.addEventListener("mousedown", function(event) { // binding mousedown event
            event.preventDefault();
            down(event)
        });

        canvas.addEventListener("touchend", function(e) { // binding mouseup event
            e.preventDefault();
            up()
        });
        parent.addEventListener("mouseup", function(e) { // binding mouseup event
            e.preventDefault();
            up()
        });

        canvas.addEventListener("touchcancel", function(e) { // binding mouseup event
            console.log("touchcancel")
        });
    }

    this.getResults = function(w,h) {
        var temp_ctx, temp_canvas;
        temp_canvas = document.createElement('canvas');
        temp_ctx = temp_canvas.getContext('2d');
        if(!w||w>theSelection.w){
            temp_canvas.width = theSelection.w;// * scale;
            temp_canvas.height = theSelection.h;// * scale;
        }else{
            temp_canvas.width = w||theSelection.w;// * scale;
            temp_canvas.height = h||theSelection.h;// * scale;
        }
        temp_ctx.drawImage(image, theSelection.x * scale, theSelection.y * scale, theSelection.w * scale, theSelection.h * scale,0,0,temp_canvas.width,temp_canvas.height);
        return temp_canvas.toDataURL();
    }
}
var pick = function(type) {
    return new Promise((resolve,reject)=>{
        var f = document.createElement('input')
        f.type = 'file';
        f.accept = type
        f.click();
        f.addEventListener('change', function(e) {
            var path = window.URL.createObjectURL(e.target.files.item(0))
            resolve(path)
        })
    })
}
module.exports = {
    pickFile: function() {
        return pick('*')
    },
    pickImage: function() {
        return pick('image/*')
    },
    pick: pick,
    crop: crop,
    toBase64: function(url,w,h, outputFormat) {
        return new Promise((resolve,reject)=>{
            var canvas = document.createElement('CANVAS'),
                ctx = canvas.getContext('2d'),
                img = new Image();
            img.crossOrigin = 'Anonymous';
            img.onload = function() {
                var scale = (w||img.width)/img.width
                canvas.height = h||img.height*scale;
                canvas.width = w||img.width;
                ctx.drawImage(img, 0, 0,canvas.width,canvas.height);
                var dataURL = canvas.toDataURL(outputFormat || 'image/jpeg');
                resolve(dataURL);
                canvas = null;
            };
            img.src = url;
        })
    }
}
